package com.young.coderule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.young.coderule.common.enums.SignTypeEnum;
import com.young.coderule.entity.ComCodeRule;
import com.young.coderule.entity.ComCodeRuleNumber;
import com.young.coderule.entity.ComCodeRuleT;
import com.young.coderule.mapper.ComCodeRuleMapper;
import com.young.coderule.service.CodeRuleCacheService;
import com.young.coderule.service.ComCodeRuleNumberService;
import com.young.coderule.service.ComCodeRuleService;
import com.young.coderule.service.ComCodeRuleTService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @DESCRIPTION: 编码规则组成service
 * @USER: Young
 */
@Service
public class ComCodeRuleServiceImpl extends ServiceImpl<ComCodeRuleMapper, ComCodeRule> implements ComCodeRuleService {

    @Autowired
    private ComCodeRuleTService comCodeRuleTService;

    @Autowired
    private ComCodeRuleNumberService comCodeRuleNumberService;

    @Autowired
    private CodeRuleCacheService codeRuleCacheService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(ComCodeRule comCodeRule) {

        this.save(comCodeRule);
        List<ComCodeRuleT> comCodeRuleTList = comCodeRule.getComCodeRuleT();
        if (null != comCodeRuleTList && !comCodeRuleTList.isEmpty()) {
            comCodeRuleTList.forEach(entity->entity.setRuleId(comCodeRule.getId()));
            comCodeRuleTService.saveBatch(comCodeRuleTList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(Serializable id) {
        this.removeById(id);
        Map<String, Object> columnMap = new HashMap<>(16);
        columnMap.put("rule_id",id);
        comCodeRuleTService.removeByMap(columnMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(ComCodeRule comCodeRule) {

        this.updateById(comCodeRule);
        Map<String, Object> columnMap = new HashMap<>(16);
        columnMap.put("rule_id",comCodeRule.getId());
        comCodeRuleTService.removeByMap(columnMap);
        List<ComCodeRuleT> comCodeRuleTList = comCodeRule.getComCodeRuleT();
        if (null != comCodeRuleTList && !comCodeRuleTList.isEmpty()) {
            comCodeRuleTList.forEach(entity->entity.setRuleId(comCodeRule.getId()));
            comCodeRuleTService.saveBatch(comCodeRuleTList);
        }
    }

    @Override
    public ComCodeRule detail(Serializable id) {
        ComCodeRule comCodeRule = this.getById(id);
        comCodeRule.setComCodeRuleT(comCodeRuleTService.list(new QueryWrapper<ComCodeRuleT>().eq("rule_id",id)));
        comCodeRule.setComCodeRuleNumber(comCodeRuleNumberService.getOne(new QueryWrapper<ComCodeRuleNumber>().eq("rule_id",id)));
        return comCodeRule;
    }

    @Override
    public ComCodeRule queryDetail(String bizObjectCode) {
        ComCodeRule comCodeRule = this.getOne(new QueryWrapper<ComCodeRule>().eq("biz_object_code", bizObjectCode), true);
        if(null == comCodeRule){
            return null;
        }
        comCodeRule.setComCodeRuleT(comCodeRuleTService.list(new QueryWrapper<ComCodeRuleT>().eq("rule_id",comCodeRule.getId())));
        comCodeRule.setComCodeRuleNumber(comCodeRuleNumberService.getOne(new QueryWrapper<ComCodeRuleNumber>().eq("rule_id",comCodeRule.getId())));
        return comCodeRule;
    }

    @Override
    public String getCode(String bizObjectCode) {
        Map<String, Object> codeMap = getCodeMap(bizObjectCode);

        return (String) codeMap.get("code");
    }

    private String getNumber(Integer num ,int length){
        NumberFormat formatter = NumberFormat.getNumberInstance();
                    formatter.setMinimumIntegerDigits(length);
                    formatter.setGroupingUsed(false);
                 return formatter.format(num);
    }

    private Map<String,Object> getCodeMap(String bizObjectCode){
        ComCodeRule comCodeRule = queryDetail(bizObjectCode);

        if(null==comCodeRule)  return new HashMap<>();

        List<ComCodeRuleT> comCodeRuleTs = comCodeRule.getComCodeRuleT();

        if(null==comCodeRuleTs||comCodeRuleTs.size()==0){
            return new HashMap<>();
        }

        Date now = new Date();
        StringBuffer sb = new StringBuffer();
        Map<String, Object> map = new HashMap<>();
        map.put("edit",comCodeRule.getIsmodifiable());
//        属性类型：1-随机码    2-常量,  3-系统日期  4-业务对象日期, 5-业务对象字段，6-流水号,
        for (ComCodeRuleT comCodeRuleT : comCodeRuleTs) {
            sb.append(SignTypeEnum.getSign(comCodeRuleT.getSplitSign()));
            Integer attributeType = comCodeRuleT.getAttributeType();
            switch (attributeType) {
                case 1:
//                    int[] ints = NumberUtil.generateRandomNumber(0, 9, 8);
                    new Random().ints(0, 9, 8).mapToObj(i -> sb.append(i));
                    break;
                case 2:
                    sb.append(comCodeRuleT.getSetValue());
                    break;
                case 3:
                    // TODO 可以支持多种日期格式
//                    String date_format = dictApi.getDictName("date_format", comCodeRuleT.getFormat());
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
                    String date = simpleDateFormat.format(now);
                    sb.append(date);
                    break;
                case 4:
                    break;
                case 5:
                    break;
                case 6:
                    /**
                     * 取号唯一保存的时候操作
                     */

                    Integer length = comCodeRuleT.getLength();
                        try {
                            //从redis 中取最大号
                            // TODO 考虑，会有并发问题吗？
                            ComCodeRuleNumber comCodeRuleNumber = codeRuleCacheService.getCodeRuleNumber(bizObjectCode);
                            if(null == comCodeRuleNumber){
                                comCodeRuleNumber = comCodeRuleNumberService.getOne(new QueryWrapper<ComCodeRuleNumber>().eq("rule_id",comCodeRule.getId()));
                                if(null == comCodeRuleNumber){
                                    comCodeRuleNumber =new ComCodeRuleNumber();
                                    comCodeRuleNumber.setRuleId(comCodeRule.getId());
                                    comCodeRuleNumber.setBigNumber(1);
                                    comCodeRuleNumber.setBizObjectCode(bizObjectCode);
                                }
                                codeRuleCacheService.putCodeRuleNumber(bizObjectCode,comCodeRuleNumber);
                            }
                            Integer bigNumber = comCodeRuleNumber.getBigNumber();
                            sb.append(getNumber(bigNumber, length));

                        } catch (Exception e) {
                            throw new RuntimeException("取流水号失败");
                        }

                    break;
                default:
                    break;
            }
        }
        map.put("code",sb.toString());
        return map;
    }

}